#include "BestFit.h"
using namespace std;

BestFit::BestFit() :
	Allocator("BestFit")
{
	areas = new list<Area*> ();
}

BestFit::~BestFit()
{
	delete areas;
}

const Area * BestFit::alloc(int wanted)
{
	for (list<Area*>::iterator it = areas->begin(); it != areas->end(); it++)
	{
		//ga lijst door tot gebied gevonden heeft dat ongeveer past
		if ((*it)->getSize() >= wanted)
		{
			Area * area = *it;
			if (area->getSize() == wanted)
			{
				areas->remove(area);
				return area;
			}
			//haal gegevens van gebied op
			int base = area->getBase();
			int size = area->getSize();
			//haal oude gebied weg
			areas->remove(area);
			//maak gebied aan dat de goede grootte heeft
			Area * fitArea = new Area(base, wanted);
			//zet rest terug in lijst.
			areas->push_back(new Area(base + wanted, size - wanted));
			return fitArea;
		}
	}
	return 0;
}

void BestFit::setSize(int new_size)
{
	Allocator::setSize(new_size);
	for (list<Area*>::iterator it = areas->begin(); it != areas->end(); it++)
	{
		delete *it;
	}
	areas->clear();
	areas->insert(areas->begin(), new Area(0, size));
}

void BestFit::free(const Area * ap)
{
	for (list<Area*>::iterator it = areas->begin(); it != areas->end(); it++)
	{
		if ((*it)->getSize() > ap->getSize())
		{
			areas->insert(it, new Area(*ap));
			return;
		}
	}
	areas->insert(areas->end(), new Area(*ap));
}

int BestFit::getUsedMemory()
{
	int totalV = size;
	int totalB = 0;

	for (list<Area*>::iterator it = areas->begin(); it != areas->end(); it++)
	{
		//tel de lege virtuele ruimte
		totalV -= (*it)->getSize();
		//tel de echte bytes grootte van area objects, iterator en pointer
		totalB += sizeof(**it) + sizeof(it) + sizeof(*it);
	}
	return totalV + totalB + sizeof(areas);
}
int BestFit::getRequiredMemory()
{
	int total = size;
	for (list<Area*>::iterator it = areas->begin(); it != areas->end(); it++)
	{
		//tel de lege virtuele bytes
		total -= (*it)->getSize();
	}
	return total;
}

double BestFit::GetFragmentationRate()
{
	double size = 0;
	double n = 0;
	for (list<Area*>::iterator it = areas->begin(); it != areas->end(); it++)
	{
		n++;
		size += (*it)->getSize();
	}
	return 1 - (1 / (n / size * size));
}
